/*
Authors: Eli Yucht 300388949 and Lior Fass 300069705
Project: Hamming
Description: Bytes Manipulation Implementation
*/

#include "Bytes_Manipulation.h"

/*
* this function takes 13 Bytes and arrange them in 16 Bytes
* each 4 bytes contatins 26 bits of info and  unused bits
* this function is used by the sender right after reading from the file
*
* Input:
* -----
* byte_array - array of 13 bytes of data
*
* Output:
* -----
* bits_block_array - array of 16 bytes with 6 empty bits after each 26(place for the parity bits)
*/
void Bytes_Man::Bytes_to_26_bits(unsigned char* byte_array, unsigned char* bits_block_array)
{

	bits_block_array[0] = byte_array[0];
	bits_block_array[1] = byte_array[1];
	bits_block_array[2] = byte_array[2];
	bits_block_array[3] = byte_array[3] & 0xc0;
	bits_block_array[4] = (byte_array[3] << 2) | (byte_array[4] >> 6);
	bits_block_array[5] = (byte_array[4] << 2) | (byte_array[5] >> 6);
	bits_block_array[6] = (byte_array[5] << 2) | (byte_array[6] >> 6);
	bits_block_array[7] = (byte_array[6] << 2) & 0xc0;
	bits_block_array[8] = (byte_array[6] << 4) | (byte_array[7] >> 4);
	bits_block_array[9] = (byte_array[7] << 4) | (byte_array[8] >> 4);
	bits_block_array[10] = (byte_array[8] << 4) | (byte_array[9] >> 4);
	bits_block_array[11] = (byte_array[9] << 4) & 0xc0;
	bits_block_array[12] = (byte_array[9] << 6) | (byte_array[10] >> 2);
	bits_block_array[13] = (byte_array[10] << 6) | (byte_array[11] >> 2);
	bits_block_array[14] = (byte_array[11] << 6) | (byte_array[12] >> 2);
	bits_block_array[15] = (byte_array[12] << 6);
}

/*
* this function compact 16 bytes holding 4 blocks of 26 bits (stored in 4 bytes) to 13 bytes
* by removing the last 6 bits in each 4 bytes block
* this function is used by the Receiver right before saving to output file
*
* Input:
* -----
* bits_block_array - array of 16 bytes with 6 "dirty" bits after each 26(the parity bits and 1 extra)
*
* Output:
* -----
* byte_array - array of 13 bytes of data
*/
void Bytes_Man::bits_26_to_Byte(unsigned char* bits_block_array, unsigned char* byte_array)
{
	byte_array[0] = bits_block_array[0];
	byte_array[1] = bits_block_array[1];
	byte_array[2] = bits_block_array[2];
	byte_array[3] = (bits_block_array[3] & 0xc0) | bits_block_array[4] >> 2;
	byte_array[4] = bits_block_array[4] << 6 | bits_block_array[5] >> 2;
	byte_array[5] = bits_block_array[5] << 6 | bits_block_array[6] >> 2;
	byte_array[6] = bits_block_array[6] << 6 | ((bits_block_array[7] >> 2) & 0x30) | bits_block_array[8] >> 4;
	byte_array[7] = bits_block_array[8] << 4 | bits_block_array[9] >> 4;
	byte_array[8] = bits_block_array[9] << 4 | bits_block_array[10] >> 4;
	byte_array[9] = bits_block_array[10] << 4 | ((bits_block_array[11] >> 4) & 0x0c) | bits_block_array[12] >> 6;
	byte_array[10] = bits_block_array[12] << 2 | bits_block_array[13] >> 6;
	byte_array[11] = bits_block_array[13] << 2 | bits_block_array[14] >> 6;
	byte_array[12] = bits_block_array[14] << 2 | bits_block_array[15] >> 6;



}

/*
* this function Compacts 32 bytes of eight 31 bits blocks into 31 bytes of 32 bits
* if used on 16 bytes of 31 bits blocks it remains 16 bytes but without 0's in the middle
* the function is used by the sender right before sending the stream to the socket
*
* Input:
* -----
* block_31 - array of 32 bytes holding 31X8 relevant bits
* num_of_blocks - int, 4 or 8 blocks.
*
* Output:
* -----
* bytes- byte array of 31 bytes - no irrelevant zeros in the middle
*/
void Bytes_Man::Block31_to_Bytes(unsigned char* block_31, unsigned char* bytes, int num_of_blocks)
{
	bytes[0] = block_31[0];
	bytes[1] = block_31[1];
	bytes[2] = block_31[2];
	bytes[3] = block_31[3] | block_31[4] >> 7;
	bytes[4] = block_31[4] << 1 | block_31[5] >> 7;
	bytes[5] = block_31[5] << 1 | block_31[6] >> 7;
	bytes[6] = block_31[6] << 1 | block_31[7] >> 7;
	bytes[7] = block_31[7] << 1 | block_31[8] >> 6;
	bytes[8] = block_31[8] << 2 | block_31[9] >> 6;
	bytes[9] = block_31[9] << 2 | block_31[10] >> 6;
	bytes[10] = block_31[10] << 2 | block_31[11] >> 6;
	bytes[11] = block_31[11] << 2 | block_31[12] >> 5;
	bytes[12] = block_31[12] << 3 | block_31[13] >> 5;
	bytes[13] = block_31[13] << 3 | block_31[14] >> 5;
	bytes[14] = block_31[14] << 3 | block_31[15] >> 5;
	if (num_of_blocks == 4)
	{
		bytes[15] = block_31[15] << 3;
		return;
	}
	//else => num_of_block == 8
	bytes[15] = block_31[15] << 3 | block_31[16] >> 4;
	bytes[16] = block_31[16] << 4 | block_31[17] >> 4;
	bytes[17] = block_31[17] << 4 | block_31[18] >> 4;
	bytes[18] = block_31[18] << 4 | block_31[19] >> 4;
	bytes[19] = block_31[19] << 4 | block_31[20] >> 3;
	bytes[20] = block_31[20] << 5 | block_31[21] >> 3;
	bytes[21] = block_31[21] << 5 | block_31[22] >> 3;
	bytes[22] = block_31[22] << 5 | block_31[23] >> 3;
	bytes[23] = block_31[23] << 5 | block_31[24] >> 2;
	bytes[24] = block_31[24] << 6 | block_31[25] >> 2;
	bytes[25] = block_31[25] << 6 | block_31[26] >> 2;
	bytes[26] = block_31[26] << 6 | block_31[27] >> 2;
	bytes[27] = block_31[27] << 6 | block_31[28] >> 1;
	bytes[28] = block_31[28] << 7 | block_31[29] >> 1;
	bytes[29] = block_31[29] << 7 | block_31[30] >> 1;
	bytes[30] = block_31[30] << 7 | block_31[31] >> 1;

}

/*
* this function spreads 31 bytes of 32 bits to 32 bytes of eight 31 bits blocks  
* if used on 16 bytes of 31 bits blocks it remains 16 bytes but with 0's in the middle
* the function is used by the Receiver right after recieving  the stream from the socket
*
* Input:
* -----
* bytes- byte array of 31 bytes - no irrelevant zeros in the middle
* num_of_blocks - int, 4 or 8 blocks.
*
* Output:
* -----
* block_31 - array of 32 bytes holding 31X8 relevant bits
*/
void Bytes_Man::Bytes_to_Block31(unsigned char* block_31, unsigned char* bytes, int num_of_blocks)
{
	block_31[0] = bytes[0];
	block_31[1] = bytes[1];
	block_31[2] = bytes[2];
	block_31[3] = bytes[3] & 0xfe;
	block_31[4] = bytes[3] << 7 | bytes[4] >> 1;
	block_31[5] = bytes[4] << 7 | bytes[5] >> 1;
	block_31[6] = bytes[5] << 7 | bytes[6] >> 1;
	block_31[7] = (bytes[6] << 7 | bytes[7] >> 1) & 0xfe;
	block_31[8] = bytes[7] << 6 | bytes[8] >> 2;
	block_31[9] = bytes[8] << 6 | bytes[9] >> 2;
	block_31[10] = bytes[9] << 6 | bytes[10] >> 2;
	block_31[11] = (bytes[10] << 6 | bytes[11] >> 2) & 0xfe;
	block_31[12] = bytes[11] << 5 | bytes[12] >> 3;
	block_31[13] = bytes[12] << 5 | bytes[13] >> 3;
	block_31[14] = bytes[13] << 5 | bytes[14] >> 3;
	block_31[15] = (bytes[14] << 5 | bytes[15] >> 3) & 0xfe;

	if (num_of_blocks == 4)
		return;

	block_31[16] = bytes[15] << 4 | bytes[16] >> 4;
	block_31[17] = bytes[16] << 4 | bytes[17] >> 4;
	block_31[18] = bytes[17] << 4 | bytes[18] >> 4;
	block_31[19] = (bytes[18] << 4 | bytes[19] >> 4) & 0xfe;
	block_31[20] = bytes[19] << 3 | bytes[20] >> 5;
	block_31[21] = bytes[20] << 3 | bytes[21] >> 5;
	block_31[22] = bytes[21] << 3 | bytes[22] >> 5;
	block_31[23] = (bytes[22] << 3 | bytes[23] >> 5) & 0xfe;
	block_31[24] = bytes[23] << 2 | bytes[24] >> 6;
	block_31[25] = bytes[24] << 2 | bytes[25] >> 6;
	block_31[26] = bytes[25] << 2 | bytes[26] >> 6;
	block_31[27] = (bytes[26] << 2 | bytes[27] >> 6) & 0xfe;
	block_31[28] = bytes[27] << 1 | bytes[28] >> 7;
	block_31[29] = bytes[28] << 1 | bytes[29] >> 7;
	block_31[30] = bytes[29] << 1 | bytes[30] >> 7;
	block_31[31] = bytes[30] << 1;
}